#pragma once

#include <iostream>
#include <sys/epoll.h>
#include <unistd.h>
#include "LogMessage.hpp"
#include "Sock.hpp"
#include "Epoll.hpp"

class EpollServer
{
public:
    EpollServer(std::string ip = "0.0.0.0", int port = 8080, int size = 20)
    {
        _listensock = _sock.Socket();
        _sock.Bind(_listensock, ip, port);
        _sock.Listen(_listensock);
        LogMessage(Debug, "server start success!");

        _events = new struct epoll_event[size];
        _events_size = size;

        // 创建epoll模型
        _epfd = Epoll::EpollCreate();
        if (_epfd < 0)
        {
            LogMessage(Error, "create epoll fd error, erron: %d  strerror: %s", errno, strerror(errno));
            exit(1);
        }
        LogMessage(Debug, "_listensock: %d   _epfd: %d", _listensock, _epfd);

        // 将_listensock交给epoll
        if (!Epoll::EpollCtrl(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN))
        {
            LogMessage(Debug, "add _listensock to epoll error");
            exit(2);
        }
        LogMessage(Debug, "add _listensock to epoll success");
    }

    ~EpollServer()
    {
        if (_listensock)
            close(_listensock);
        if (_epfd)
            close(_epfd);
        if (_events)
            delete[] _events;
    }

    void Handler(int n)
    {
        for (int i = 0; i < n; i++)
        {
            int eve = _events[i].events;
            int fd = _events[i].data.fd;

            if (eve & EPOLLIN == 1)
            {
                if (fd == _listensock)
                    Accept();
                else
                    Recv(fd);
            }
        }
    }

    void Accept()
    {
        std::string ip;
        uint16_t port;
        int serverSock = _sock.Accept(_listensock, &ip, &port);
        if (serverSock > 0)
        {
            if (Epoll::EpollCtrl(_epfd, EPOLL_CTL_ADD, serverSock, EPOLLIN))
            {
                LogMessage(Debug, "%s  %d link success", ip.c_str(), port);
            }
        }
    }

    void Recv(int sockfd)
    {
        std::string buffer;
        int n = _sock.Revc(sockfd, buffer);
        if (n > 0)
        {
            buffer.pop_back();
            buffer.pop_back();
            LogMessage(Debug, "recv message success:  %s", buffer.c_str());
        }
        else if (n == 0)
        {
            //对端关闭
            LogMessage(Debug, "you close fd, me too");
            Epoll::EpollCtrl(_epfd, EPOLL_CTL_DEL, sockfd, EPOLLIN);
            close(sockfd);
        }
        else 
        {
            LogMessage(Warning, "recv message error, errno: %d strerror: %s", errno, strerror(errno));
        }
    }

    void LoopOnce(int timeout)
    {
        // epoll_wait的返回值即为events中有效数据的个数
        int n = Epoll::EpollWait(_epfd, _events, _events_size, timeout);
        if (n > 0)
        {
            LogMessage(Debug, "get a event");
            Handler(n);
        }
        else if (n == 0)
        {
            LogMessage(Debug, "time out");
        }
        else
        {
            LogMessage(Warning, "epollwait error,  errno:%d  strerror:%s", errno, strerror(errno));
        }
    }

    void Start()
    {
        while (true)
        {
            LoopOnce(1000);
        }
    }

private:
    int _listensock;
    Sock _sock;
    int _epfd;
    struct epoll_event *_events;
    int _events_size;
};